/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine - visibility
// Copyright (c) 2015.  All Rights Reserved
//
// File:		AEVisibilityZone.h
// Author:		Gianluca Belardelli
// Date:		30/06/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEVISIBILITYZONE_H_
#define _AEVISIBILITYZONE_H_

/// \brief
///   Class describing a visibility zone.
/// 
/// A visibility zone is basically a volume containing scene elements. During visibility
/// determination, the visibility collector (see IVisVisibilityCollector_cl) traverses the
/// visibility zones and determines which zones and which scene elements inside these zones are
/// visible. Visibility zones are either connected through portals or directly. Portals are
/// typically used in indoor scenes, where a large part of the scene is always occluded. Direct
/// connections between visibility zones can be used to subdivide large open spaces and therefore
/// improve visibility determination performance.
/// 
/// Scene elements can be in zero, one or multiple visibility zones at the same time. Transitions
/// of scene elements through portals or into neighboring visibility zones are handled
/// automatically using the functionality provided by the VisObject3DVisData_cl class.
/// 
/// Visibility zones have to be added to the active scene manager (see IVisSceneManager_cl) before
/// they are used.
/// 
/// Visibility zones are always represented by an axis-aligned bounding box. While a visibility
/// zone MAY NOT overlap any of the visibility zones directly connected to it (though it has to
/// touch them), it MAY overlap visibility zones connected through portals. This is due to the fact
/// that portals are basically determined by the scene geometry and can be at arbitrary locations
/// and arbitrary angles.
/// 
/// Note that all portals connected with a visibility zone have to be completely inside the
/// bounding box of that visibility zone.
/// 
/// Custom implementations may derive classes from VisVisibilityZone_cl and implement some of the
/// virtual functions.
class AEVisibilityZone : public AEReferencedObject
{
// Members
protected:
	AEStaticGeometryInstanceCollection *m_lpStaticGeometryInstances;

	AEUINT32		m_uiZoneFlags;
	AEBoundingBox	m_bbBoundingBox;

// Methods
public:
	/** @name Construction / Destruction */
	/// @{
	/// \brief
	///   Constructs a new visibility zones with the given bounding box.
	AE_DLLIMPEXP AEVisibilityZone( const AEBoundingBox &bbBox );

	/// \brief
	///   Default constructor. Initializes the visibility zone's bounding box as empty.
	AE_DLLIMPEXP AEVisibilityZone( void );

	/// \brief Distruttore della classe AEVisibilityZone.
	AE_DLLIMPEXP ~AEVisibilityZone( void );

	/** @name Flags */
	/// @{
	/// \brief
	///   Set the bit flag constants for this zone. These constants are of type
	///   VIS_VISIBILITYZONEFLAGS_xyz)
	AE_FORCEINLINE void SetZoneFlags( AEUINT32 uiFlags );

	/// \brief
	///   Get the bit flag constants for this zone. These constants are of type
	///   VIS_VISIBILITYZONEFLAGS_xyz)
	AE_FORCEINLINE AEUINT32 GetZoneFlags( void ) const;

	/// @}
	/** @name Scene Element Handling */
	/// @{
	/// \brief
	///   Returns the minimum distance of the passed bounding box to the static geometry in the
	///   visibility zone.
	/// 
	/// Since this method actually computes the distance between the box and the indvidual static
	/// geometry inside the visibility zone, this method may take some time to finish. It is,
	/// however, required for accurate assigment of dynamic scene elements to visibility zones.
	/// 
	/// \param RefBox
	///   The bounding box to test.
	/// 
	/// \param pBestGeoInstance
	///   Pointer to the closest geometry instance found.
	/// 
	/// \return
	///   float: Distance of the closest static geometry instance to the center of the box in world
	///   units.
	AE_DLLIMPEXP AEFLOAT32 GetDistanceFromGeometry( const AEBoundingBox &bbRefBox, AEStaticGeometryInstance *&lpBestGeoInstance ) const;

	/// \brief
	///   Returns a collection containing all static geometry instances in this visibility zone
	/// 
	/// Note that scene elements may be in multiple visibility zones at the same time. 
	/// 
	/// \return
	///   VisStaticGeometryInstanceCollection_cl *: Collection of all static geometry instances in
	///   this zone.
	AE_DLLIMPEXP inline const AEStaticGeometryInstanceCollection *GetStaticGeometryInstances( void )
	{ 
		return m_lpStaticGeometryInstances; 
	}

	/// @}
	/** @name Bounding Box */
	/// @{
	/// \brief
	///   Returns the bounding box of this visibility zone.
	AE_FORCEINLINE const AEBoundingBox &GetBoundingBox( void ) const;

	/// \brief
	///   Sets the bounding box of this visibility zone.
	AE_DLLIMPEXP void SetBoundingBox( const AEBoundingBox &bbBox );

	/// @}
	/** @name Adding/removing Scene Elements */
	/// @{
	/// \brief
	///   Adds a static geometry instance to this visibility zone
	/// 
	/// Scene elements may be assigned to multiple visibility zones.
	/// 
	/// \param pGeomInstance
	///   Static geometry instance to add.
	AE_DLLIMPEXP void AddStaticGeometryInstance( AEStaticGeometryInstance *lpGeomInstance );

	/// \brief
	///   Removes a static geometry instance from the visibility zone
	AE_DLLIMPEXP void RemoveGeometryInstance( AEStaticGeometryInstance *lpGeomInstance );
};

#include "AEVisibilityZone.inl"
#endif // _AEVISIBILITYZONE_H_
